package cn.dianchiyun.protocol.netty.dtu.handler.impl;

import cn.dianchiyun.protocol.Const;
import cn.dianchiyun.protocol.netty.dtu.ChannelManager;
import cn.dianchiyun.protocol.netty.dtu.entity.DTUWrite;
import cn.dianchiyun.protocol.netty.utils.ByteUtil;
import cn.dianchiyun.protocol.netty.utils.ConvertCode;
import cn.dianchiyun.protocol.netty.utils.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * @version 1.0
 * @author: weir
 * @date: 2020/6/1 11:09 AM
 */
public class ServerHandler extends ChannelHandlerAdapter {
    private static final Logger logger = LogManager.getLogger("dtu_server");

    public void channelRead(ChannelHandlerContext channel, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);//复制内容到字节数组bytes
        String receiveStr = HexUtil.receiveHexToString(bytes);//将接收到的数据转为字符串，此字符串就是客户端发送的字符串
        //System.out.println("receiveHexToString收到数据:" + ConvertCode.receiveHexToString(bytes));
        //System.out.println("         bytes2Str收到数据:" + ConvertCode.bytes2Str(bytes));
        //System.out.println("   bytes2HexString收到数据:" + ConvertCode.bytes2HexString(bytes));
        System.out.println(bytes.length);
        if(bytes.length == 12 && receiveStr.toLowerCase().startsWith("ff10") && receiveStr.toLowerCase().endsWith("ff11")){
            String serialCode = receiveStr.substring(4, 20);
            System.out.println("设备注册码："+ serialCode);
            //返回16进制到客户端
            DTUWrite dtuWrite0 = new DTUWrite("01", "04", 0, 11);
            writeToClient(dtuWrite0, channel, "测试1");
            Thread.sleep(2000);
            DTUWrite dtuWrite11 = new DTUWrite("01", "04", 11, 1);
            writeToClient(dtuWrite11, channel, "测试2");
            Thread.sleep(2000);
            DTUWrite dtuWrite24 = new DTUWrite("01", "04", 24, 1);
            writeToClient(dtuWrite24, channel, "测试3");
            Thread.sleep(2000);
            DTUWrite dtuWrite50 = new DTUWrite("01", "04", 50, 24);
            writeToClient(dtuWrite50, channel, "电压测试");
            Thread.sleep(2000);
            DTUWrite dtuWrite350 = new DTUWrite("01", "04", 350, 25);
            writeToClient(dtuWrite350, channel, "内阻测试");
            Thread.sleep(2000);
            DTUWrite dtuWrite650 = new DTUWrite("01", "04", 650, 26);
            writeToClient(dtuWrite650, channel, "温度测试");

            return;
        }else {
            int indexNow = 0;
            /*byte[] code = Arrays.copyOfRange(bytes, indexNow, indexNow + 12);
            indexNow += 12;
            System.out.println(new String(code));*/

            byte address = bytes[indexNow];
            indexNow += 1;
            System.out.println("address char:" + address);
            if (address == 0x01) {
                System.out.println("address:" + HexUtil.bytes2Byte255(address));
            }

            byte funCode = bytes[indexNow];
            indexNow += 1;
            System.out.println("funCode char:" + (char) funCode);
            if (funCode == 0x04) {
                System.out.println("funCode:" + HexUtil.bytes2Byte255(funCode));
            }

            byte lengthByte = bytes[indexNow];
            indexNow += 1;
            int dataLength = HexUtil.bytes2Byte255(lengthByte) / 2;

            System.out.print("数据:");
            for (int i = 0; i < dataLength; i++) {
                System.out.print(ByteUtil.getInt(new byte[]{bytes[indexNow + 1], bytes[indexNow]}, true) + "\t");
                indexNow += 2;
            }
            System.out.println("\t");

        }
    }

    /**
     * 公用回写数据到客户端的方法
     *
     * @param dtuWrite 需要回写的字符串
     * @param channel
     * @param mark       用于打印/log的输出
     *                   <br>//channel.writeAndFlush(msg);//不行
     *                   <br>//channel.writeAndFlush(receiveStr.getBytes());//不行
     *                   <br>在netty里，进出的都是ByteBuf，楼主应确定服务端是否有对应的编码器，将字符串转化为ByteBuf
     */
    private void writeToClient(final DTUWrite dtuWrite, ChannelHandlerContext channel, final String mark) {
        try {
            String receiveStr = dtuWrite.getCRCString();
            ByteBuf buf = Unpooled.buffer();//netty需要用ByteBuf传输
            buf.writeBytes(ConvertCode.hexString2Bytes(receiveStr)); //对接需要16进制
            channel.writeAndFlush(dtuWrite).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    StringBuilder sb = new StringBuilder("");
                    if (!StringUtils.isEmpty(mark)) {
                        sb.append("【").append(mark).append("】");
                    }
                    if (future.isSuccess()) {
                        System.out.println(sb.toString() + "回写成功" + receiveStr);
                        logger.info(sb.toString() + "回写成功" + receiveStr);
                    } else {
                        System.out.println(sb.toString() + "回写失败" + receiveStr);
                        logger.error(sb.toString() + "回写失败" + receiveStr);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("调用通用writeToClient()异常" + e.getMessage());
            logger.error("调用通用writeToClient()异常：", e);
        }
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception{
        logger.info("channelActive>>>>>>>>已连接");
        super.channelActive(ctx);
        logger.info("ctx.name():"+ctx.name());
        logger.info("ctx.channel().id():"+ctx.channel().id());
        logger.info("ctx.channel().localAddress():"+ctx.channel().localAddress());
        logger.info("ctx.channel().remoteAddress():"+ctx.channel().remoteAddress());

        ChannelManager.getInstance().addChannel(ctx.channel().remoteAddress().toString(), ctx.channel());
    }

    /**
     * 客户端关闭的处理
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("channelInactive>>>>>>>>已断开连接");
        super.channelInactive(ctx);
        ChannelManager.getInstance().remove(ctx.channel());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        logger.info("已经"+ Const.TIMEOUT+"秒未收到客户端的消息了！");
        if (evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent)evt;
            if (event.state() == IdleState.READER_IDLE){
                logger.error("关闭这个不活跃通道！");
                ctx.channel().close();
            }
        }else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

}
